package com.zbkj.crmeb.finance.service.impl;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Optional;

import javax.annotation.Resource;

import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.common.CommonPage;
import com.common.PageParamRequest;
import com.constants.Constants;
import com.crmeb.core.exception.CrmebException;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.utils.CrmebUtil;
import com.utils.DateUtil;
import com.zbkj.crmeb.chant.model.ChannelMerchant;
import com.zbkj.crmeb.chant.model.ChannelMerchantAccount;
import com.zbkj.crmeb.chant.service.IChannelMerchantAccountService;
import com.zbkj.crmeb.chant.service.IChannelMerchantService;
import com.zbkj.crmeb.enums.AccountFlowTypeEnum;
import com.zbkj.crmeb.finance.dao.UserRechargeDao;
import com.zbkj.crmeb.finance.model.UserRecharge;
import com.zbkj.crmeb.finance.request.GetListRequest;
import com.zbkj.crmeb.finance.request.UserRechargeSearchRequest;
import com.zbkj.crmeb.finance.response.UserRechargeResponse;
import com.zbkj.crmeb.finance.service.UserRechargeService;
import com.zbkj.crmeb.front.request.UserRechargeRequest;
import com.zbkj.crmeb.store.service.AccountFlowService;
import com.zbkj.crmeb.system.model.SystemAdmin;
import com.zbkj.crmeb.system.service.SystemAdminService;
import com.zbkj.crmeb.user.model.User;
import com.zbkj.crmeb.user.service.UserService;

import lombok.extern.slf4j.Slf4j;

/**
* @author Mr.Zhang
* @Description UserRechargeServiceImpl 接口实现
* @since  2020-05-11
*/
@Slf4j
@Service
@Transactional
public class UserRechargeServiceImpl extends ServiceImpl<UserRechargeDao, UserRecharge> implements UserRechargeService {
    @Resource
    private UserRechargeDao dao;
    @Autowired
    private IChannelMerchantService channelMerchantService;
    @Autowired
    private IChannelMerchantAccountService channelMerchantAccountService;
    @Autowired
    private SystemAdminService systemAdminService;
    @Autowired
    private AccountFlowService accountFlowService;
    @Autowired
    private UserRechargeService userRechargeService;
    @Autowired
    private UserService userService;

    /**
    * 列表
    * @param request 请求参数
    * @param pageParamRequest 分页类参数
    * @author Mr.Zhang
    * @since 2020-05-11
    * @return List<UserRecharge>
    */
    @Override
    public List<UserRechargeResponse> getList(UserRechargeSearchRequest request, PageParamRequest pageParamRequest) {
        PageHelper.startPage(pageParamRequest.getPage(), pageParamRequest.getLimit());

        //带 UserExtract 类的多条件查询
        LambdaQueryWrapper<UserRecharge> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        if(!StringUtils.isBlank(request.getKeywords())){
            lambdaQueryWrapper.and(i -> i.
                    or().like(UserRecharge::getUid, request.getKeywords()). //充值用户UID
                    or().eq(UserRecharge::getOrderId, request.getKeywords()) //订单号
            );
        }

        //是否充值
        if(request.getPaid() != null){
            lambdaQueryWrapper.eq(UserRecharge::getPaid, request.getPaid());
        }
        if(request.getType() != null){
            lambdaQueryWrapper.eq(UserRecharge::getType, request.getType());
        }

        //时间范围
        if(request.getStartTime() != null && request.getEndTime() != null){
            //判断时间
            int compareDateResult = DateUtil.compareDate(request.getEndTime(), request.getStartTime(), Constants.DATE_FORMAT);
            if(compareDateResult == -1){
                throw new CrmebException("开始时间不能大于结束时间！");
            }

            lambdaQueryWrapper.between(UserRecharge::getCreateTime, request.getStartTime(), request.getEndTime());
        }

        List<UserRecharge> userRecharges = dao.selectList(lambdaQueryWrapper);
        List<UserRechargeResponse> userRechargeResponses = new ArrayList<UserRechargeResponse>();
        for(UserRecharge userRecharge : userRecharges) {
            UserRechargeResponse userRechargeResponse = new UserRechargeResponse();
            BeanUtils.copyProperties(userRecharge, userRechargeResponse);
            if(null != userRecharge.getMerId()) {
                ChannelMerchant channelMerchant = channelMerchantService.getById(userRecharge.getMerId());
                userRechargeResponse.setMerName(channelMerchant.getChannelName());
            }
            userRechargeResponses.add(userRechargeResponse);
        }
        
        return userRechargeResponses;
    }

    /**
     * 根据交易类型获得分页列表
     * @param request
     * @return
     */
    @Override
    public List<UserRechargeResponse> getListByTradeType(GetListRequest request) {
        if(request.getStartTime() != null && request.getEndTime() != null) {
            if (request.getStartTime().compareTo(request.getEndTime()) > 0) {
                throw new CrmebException("开始时间不能大于结束时间！");
            }
        }
        request.setMerIds(systemAdminService.getAdminMerIds());
        PageHelper.startPage(request.getPage(), request.getLimit());
        return dao.getListByTradeType(request);
    }

    /**
     * 充值总金额
     * @author Mr.Zhang
     * @since 2020-05-11
     * @return HashMap<String, BigDecimal>
     */
    @Override
    public HashMap<String, BigDecimal> getBalanceList() {
        HashMap<String, BigDecimal> map = new HashMap<>();

        BigDecimal routine = dao.getSumByType("routine");
        map.put("routine", routine); //小程序充值

        BigDecimal weChat = dao.getSumByType("weixin");
        map.put("weChat", weChat); //公众号充值

        BigDecimal total = dao.getSumByType("");
        map.put("total", total); //总金额

        map.put("other", total.subtract(routine).subtract(weChat)); //其他金额

        return map;
    }

    /**
     * 根据对象查询订单
     * @author Mr.Zhang
     * @since 2020-05-11
     * @return UserRecharge
     */
    @Override
    public UserRecharge getInfoByEntity(UserRecharge userRecharge) {
        LambdaQueryWrapper<UserRecharge> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.setEntity(userRecharge);
        return dao.selectOne(lambdaQueryWrapper);
    }

    /**
     * 创建订单对象
     * @author Mr.Zhang
     * @since 2020-05-11
     * @return UserRecharge
     */
    @Override
    public UserRecharge create(UserRechargeRequest request) {
        UserRecharge userRecharge = new UserRecharge();
        userRecharge.setUid(request.getUserId());
        userRecharge.setMerId(request.getMerId());
        userRecharge.setOrderId(CrmebUtil.getOrderNo(Constants.PAY_TYPE_WE_CHAT));
        userRecharge.setPrice(request.getPrice());
        userRecharge.setGivePrice(request.getGivePrice());
        userRecharge.setRechargeType(request.getFromType());
        userRecharge.setPayments(request.getPayments());
        userRecharge.setType(request.getType());
        if("system".equals(request.getPayType())){
            userRecharge.setPaid(true);
            userRecharge.setPayTime(new Date());
        }
        save(userRecharge);
        return userRecharge;
    }

    /**
     * 更新充值订单
     * @param userRecharge UserRecharge 充值订单数据
     * @author Mr.Zhang
     * @since 2020-07-01
     */
    @Override
    public Boolean complete(UserRecharge userRecharge) {
        try{
            userRecharge.setPaid(true);
            userRecharge.setPayTime(DateUtil.nowDateTime());
            return updateById(userRecharge);
        }catch (Exception e){
            throw new CrmebException("回调失败！, 更新状态失败！");
        }
    }

    /**
     * 充值总金额
     * @param userId Integer 用户uid
     * @author Mr.Zhang
     * @since 2020-05-29
     * @return UserBill
     */
    @Override
    public BigDecimal getSumBigDecimal(Integer userId) {
        QueryWrapper<UserRecharge> queryWrapper = new QueryWrapper<>();


        queryWrapper.select("sum(price) as price").
                eq("uid", userId).
                eq("paid", 1);
        UserRecharge userRecharge = dao.selectOne(queryWrapper);
        if(null == userRecharge || null == userRecharge.getPrice()){
            return BigDecimal.ZERO;
        }
        return userRecharge.getPrice();
    }
    
    /**
     * 分页查询
     */
    @Override
    public PageInfo<UserRecharge> pageEntity(UserRechargeRequest request) {
        Page<Object> page = PageHelper.startPage(request.getPageNow(), request.getPageSize());
        List<UserRecharge> response = this.list(Wrappers.<UserRecharge>lambdaQuery()
                .eq(UserRecharge :: getMerId, request.getMerId())
                .eq(UserRecharge :: getType, request.getType())
                );
        
        return CommonPage.copyPageInfo(page, response);
    }

    @Override
    public Boolean withdrawAccount(BigDecimal account, String ip) {
        SystemAdmin admin = systemAdminService.getInfo();
        String merId = admin.getMerId();
        if(merId.startsWith("[")) {
        	merId = JSONArray.parseArray(merId).getString(0);
        }
        // 余额校验
        ChannelMerchantAccount channelMerchantAccount = channelMerchantAccountService.getOne(Wrappers.<ChannelMerchantAccount>lambdaQuery()
                .eq(ChannelMerchantAccount :: getMerId, merId)
                );
        if(channelMerchantAccount.getWithdrawAccount().compareTo(account) == -1) {
            throw new CrmebException("当前可提现余额不足!");
        }
        
        // 账户余额计算
        ChannelMerchantAccount channelMerchantAccountCalc = new ChannelMerchantAccount();
        channelMerchantAccountCalc.setMerId(channelMerchantAccount.getMerId());
        channelMerchantAccountCalc.setAccount(account);
        channelMerchantAccountCalc.setWithdrawAccount(BigDecimal.ZERO.subtract(account));
        channelMerchantAccountCalc.setCloseMoney(account);
        int count = channelMerchantAccountService.calcMoney(channelMerchantAccountCalc);
        if(1 > count) {
            channelMerchantAccount = channelMerchantAccountService.getById(channelMerchantAccount.getId());
            log.info("商户: {}, 余额: {}转出失败! 账户剩余: {}", channelMerchantAccount.getMerId(), account, channelMerchantAccount.getWithdrawAccount());
            throw new CrmebException("操作失败! 请联系客服!");
        }

        UserRecharge userRecharge = new UserRecharge();
        userRecharge.setMerId(channelMerchantAccount.getMerId());
        userRecharge.setUid(admin.getId());
        userRecharge.setOrderId(CrmebUtil.getOrderNo(Constants.PAY_TYPE_WE_CHAT));
        userRecharge.setPrice(account);
        userRecharge.setType(true);
        userRecharge.setStatus(1);
        userRecharge.setTradeType(3);
        userRecharge.setRechargeType(Constants.PAY_TYPE_WE_CHAT_FROM_PROGRAM);
        userRecharge.setPaid(false);
        userRecharge.setIp(ip);
        userRecharge.setCreateTime(new Date());
        userRecharge.setPayTime(new Date());
        userRecharge.setUpdateTime(new Date());
        userRechargeService.save(userRecharge);
        
        // 资金流水
        accountFlowService.saveAccountFlow(Integer.parseInt(merId), userRecharge.getId(), admin.getId(), ip, AccountFlowTypeEnum.RECHARGE, account, account.negate(), null, "商户可提现余额转出");
        
        return true;
    }

    @Override
    public UserRechargeResponse getRechargeInfo(Integer id) {
        UserRecharge userRecharge = getById(id);
        if(userRecharge == null){
            throw new CrmebException("记录不存在!");
        }
        UserRechargeResponse userRechargeResponse = new UserRechargeResponse();
        BeanUtils.copyProperties(userRecharge, userRechargeResponse);
        ChannelMerchant channelMerchant = channelMerchantService.getById(userRecharge.getMerId());
        if(channelMerchant != null){
            userRechargeResponse.setMerName(channelMerchant.getChannelName());
            userRechargeResponse.setMerCreateTime(channelMerchant.getCreateTime());
        }
        //用户支付
        if(BooleanUtils.isFalse(userRecharge.getType())){
            User user = Optional.ofNullable(userService.getById(userRechargeResponse.getUid())).orElse(new User());
            userRechargeResponse.setUName(user.getNickname());
            userRechargeResponse.setUPhone(user.getPhone());
            userRechargeResponse.setUAvatar(user.getAvatar());
        }
        //管理员
        if(BooleanUtils.isTrue(userRecharge.getType())){
            SystemAdmin systemAdmin = Optional.ofNullable(systemAdminService.getById(userRechargeResponse.getUid())).orElse(new SystemAdmin());
            userRechargeResponse.setUName(systemAdmin.getRealName());
        }
        userRechargeResponse.setUrlList(StringUtils.isNotBlank(userRecharge.getCredentials()) ? Arrays.asList(userRecharge.getCredentials().split(",")):null);
        return userRechargeResponse;
    }

}

